今天我們來學習如何利用少於200行的Python script,自動生成一個LS-DYNA模型,並自動提交求解。
這個模型會有兩個物件,在LS-DYNA裡我們叫他們做part
。值得一提的是,這個part
是LS-DYNA裡的part
,並非是ANSA裡做為container
的part
。聽不太懂?!那正常,因為我們一開始也時常搞錯...
第一個part
我們叫它做plate
,由一個QUAD4 element
組成。另一個part
我們叫它做box
,由六個QUAD4 element
組成。box
將會有個初速向下,去撞擊固定在地上的plate
。
這個project總共分為八個部份:
為減輕大家學習的難度,我們這個project先只在單一function
內完成所有事項,並在material
及property
的建立先使用預設值(註1
),等大家比較熟悉ANSA API了,我們再試著重覆或需要做細部設定的地方找出來,寫成function
或class
。此外,這個project,我們會使用numpy
及SciPy
(註2
)。
我們試著盡量逐行講解,讓大家能夠打好基礎。今天我們先講解第一到第三部份,[Day07]繼續講解第四到第八部份。
首先,我們從ANSA內import兩個所需的module
,base
及constants
。
from ansa import base, constants
接著建立一個deck
,
deck = constants.LSDYNA
再來,我們呼叫base.SetCurrentDeck
,把deck
傳進去,這步是告訴ANSA,把GUI環境內的deck
設為此deck
。如果只是寫一個NO-GUI的script,那麼這個設定不是必須的。但是因為之後我們會想在GUI內,先觀察我們產生的plate
、box
及其它設定是否如我們所想,所以我們先在前面做這個設定。
base.SetCurrentDeck(deck)
完成基本設定後,我們可以準備創建plate
。plate
是一個LS-DYNA的QUAD4 element
,由四個node
組成。
我們可以將這個小節拆成三個step:
node Entity
,命名分別node1~node4
。element Entity
,是由node1~node4
所組成,命名為plate_shell
。set
來裝載plate_shell
,命名為plate_set
。這個set
的用途是之後方便用來做接觸及邊界條件設定。我們逐個step來看。
透過base.CreateEntity
來創建node Entity
。base.CreateEntity
的基本介紹可以參考Day03的說明。
element_type
經由GUI介面可以得知其名稱為NODE
。fields
是此Entity
真正包含的內容,需為dict
型態,key
是LS-DYNA卡片內各列的參數名,value
則是我們想賦予的值。此處NID
為node
這種Entity
的id
,XYZ
則為座標值。
依照這個原則,我們可以建立四個node Entity
,其可以組成邊長為100
的正方形。
node1 = base.CreateEntity(
deck, 'NODE', {'NID': 1, 'X': 0, 'Y': 0, 'Z': 0})
node2 = base.CreateEntity(
deck, 'NODE', {'NID': 2, 'X': 100, 'Y': 0, 'Z': 0})
node3 = base.CreateEntity(
deck, 'NODE', {'NID': 3, 'X': 100, 'Y': 100, 'Z': 0})
node4 = base.CreateEntity(
deck, 'NODE', {'NID': 4, 'X': 0, 'Y': 100, 'Z': 0})
shell
的element type
為ELEMENT_SHELL
。因為我們想建立的是QUAD4
,所以fields
的type
內需指定為QUAD
,至於PID
是指property id
,因為我們還沒產生,所以可以先隨便指定一個數字,ANSA若發現這是未使用的PID
,會幫我們建立一個相對應的property Entity
及material Entity
,我們此處給1
。element id
我們也指定為1
,N1~N4
則分別指定為step1
所產生的node1~node4 Entity
。最後,命名此Entity
為plate_shell
。
plate_shell = base.CreateEntity(deck, 'ELEMENT_SHELL', {'TYPE': 'QUAD',
'PID': 1,
'EID': 1,
'N1': node1,
'N2': node2,
'N3': node3,
'N4': node4})
set
的element type
為SET
。我們建立一個名為plate_set
的Entity
,其fields
內的Name
則給定一個plate
的名字。接著我們透過base.AddToSet
將step2
產生的plate_shell
放進plate_set
內。
plate_set = base.CreateEntity(deck, 'SET', {'Name': 'plate'})
base.AddToSet(plate_set, plate_shell)
box
是由六個QUAD4 element
組成,步驟與plate很像,我們也可以將此小節拆成三個步驟:
node Entity
,命名分別node10001~node10008
。element Entity
,是由node10001~node10008
所組成,命名為box_shell1~box_shell6
,並用一個list
裝載他們,命名為box_shell
。set
來裝載box_shell
,命名為box_set
。這個set
一樣是方便之後用來做contact
設定。node10001~node10008
可以組成邊長50mm
的正立方體。我們將box
的底部預設為離地5mm
,所以將node10001~node100004
的z
設為5
(註3
)。
# box bottom layer
node10001 = base.CreateEntity(
deck, 'NODE', {'NID': 10001, 'X': 25, 'Y': 25, 'Z': 5})
node10002 = base.CreateEntity(
deck, 'NODE', {'NID': 10002, 'X': 75, 'Y': 25, 'Z': 5})
node10003 = base.CreateEntity(
deck, 'NODE', {'NID': 10003, 'X': 75, 'Y': 75, 'Z': 5})
node10004 = base.CreateEntity(
deck, 'NODE', {'NID': 10004, 'X': 25, 'Y': 75, 'Z': 5})
# box top layer
node10005 = base.CreateEntity(
deck, 'NODE', {'NID': 10005, 'X': 25, 'Y': 25, 'Z': 55})
node10006 = base.CreateEntity(
deck, 'NODE', {'NID': 10006, 'X': 75, 'Y': 25, 'Z': 55})
node10007 = base.CreateEntity(
deck, 'NODE', {'NID': 10007, 'X': 75, 'Y': 75, 'Z': 55})
node10008 = base.CreateEntity(
deck, 'NODE', {'NID': 10008, 'X': 25, 'Y': 75, 'Z': 55})
六個element entity
分別命名為box_shell1~box_shell6
,pid
都指定為2
,由ANSA自動產生property
及material Entity
,EID
則分別為 10001~10006
。各個Entity
的N1~N4
則可能需要大家畫個圖,自己看座標填入適當的node Entity
。最後再將box_shell1~box_shell6
都裝入box_shell
這個list
。
box_shell1 = base.CreateEntity(deck, 'ELEMENT_SHELL', {'TYPE': 'QUAD',
'PID': 2,
'EID': 10001,
'N1': node10004,
'N2': node10003,
'N3': node10002,
'N4': node10001})
box_shell2 = base.CreateEntity(deck, 'ELEMENT_SHELL', {'TYPE': 'QUAD',
'PID': 2,
'EID': 10002,
'N1': node10001,
'N2': node10002,
'N3': node10006,
'N4': node10005})
box_shell3 = base.CreateEntity(deck, 'ELEMENT_SHELL', {'TYPE': 'QUAD',
'PID': 2,
'EID': 10003,
'N1': node10002,
'N2': node10003,
'N3': node10007,
'N4': node10006})
box_shell4 = base.CreateEntity(deck, 'ELEMENT_SHELL', {'TYPE': 'QUAD',
'PID': 2,
'EID': 10004,
'N1': node10004,
'N2': node10001,
'N3': node10005,
'N4': node10008})
box_shell5 = base.CreateEntity(deck, 'ELEMENT_SHELL', {'TYPE': 'QUAD',
'PID': 2,
'EID': 10005,
'N1': node10003,
'N2': node10004,
'N3': node10008,
'N4': node10007})
box_shell6 = base.CreateEntity(deck, 'ELEMENT_SHELL', {'TYPE': 'QUAD',
'PID': 2,
'EID': 10006,
'N1': node10005,
'N2': node10006,
'N3': node10007,
'N4': node10008})
box_shells = [box_shell1, box_shell2, box_shell3,
box_shell4, box_shell5, box_shell6]
建立一個名為box_set
的Entity
,其fields
內的Name
則給定一個box
的名字。接著我們透過base.AddToSet
將step2
產生的box_shell
放進box_set內。
值得注意的是base.AddToSet
除了支援放入單一的Entity
,也可以放入一個內含多個Entity
的list
,所以我們可以直接將box_shell
放進box_set
。
box_set = base.CreateEntity(deck, 'SET', {'Name': 'box'})
base.AddToSet(box_set, box_shells)
註1:理論上,LS-DYNA是沒有預設單位的,所有輸入的數字都反映了使用者想模擬的世界。但因為這邊我們利用了ANSA自動產生material
及property
的功能,所以這個模擬世界的單位,將會是ANSA預設的ton/mm/sec
。
註2:ANSA
共附了numpy
、SciPy
、OpenSSL
、H5py
及randomcolor
等五個third-party package
。
註3:聰明的你可能會發現,這樣設定,相距不是5啊?沒錯,嚴格來說,plate
及box
的預設厚度皆為1mm
,實際相距會是(5-2*1/2)=4mm
。這樣都被你發現,果然是行家呀!